package com.lap.codegen.core.impl;

import com.lap.codegen.core.ContextManager;
import com.lap.codegen.domain.*;
import com.lap.codegen.exception.ManagerException;
import com.lap.codegen.utils.FileUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Objects;
import java.util.Properties;
import java.util.concurrent.*;

/**
 * <pre>
 * 上下文初始化
 * </pre>
 *
 * @author Shuisheng.Lao , 021(poker0325@me.com)
 * @version 1.0.0
 */
@Service
public class DefaultContextManager implements ContextManager {
    private final Logger logger = LoggerFactory.getLogger(this.getClass());

    @Override
    public CodeContext init() throws ManagerException {
        Properties properties;
        try {
            properties = this.getProp();
        } catch (IOException e) {
            throw new ManagerException(e);
        }
        CodeContext context = new CodeContext();
        context.setProperties(properties);
        ExecutorService executor = new ThreadPoolExecutor(5, 5, 5, TimeUnit.SECONDS, new LinkedBlockingDeque<>(1 << 4));
        CompletionService<Integer> service = new ExecutorCompletionService(executor);
        this.initConf(context, service);
        this.initDb(context, service);
        this.initPackage(context, service);
        this.initExt(context, service);
        this.initFrame(context, service);

        executor.shutdown();

        for (int i = 0; i < 5; i++) {
            try {
                Future<Integer> future = service.take();
                Integer result = future.get();
                logger.info("context init {},{}", i, result);
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
                throw new ManagerException(e);
            } catch (ExecutionException e) {
                throw new ManagerException(e);
            }
        }
        return context;
    }

    /**
     * 文件名称
     *
     * @return Properties
     * @throws IOException
     */
    private Properties getProp() throws IOException {
        String path = FileUtils.getRunPath() + "/config/config.xml";
        Properties properties = new Properties();

        try (InputStream in = new FileInputStream(new File(path))) {
            properties.loadFromXML(in);
        }
        return properties;
    }

    /**
     * <pre>
     *  并行初始化基本的配置信息
     * </pre>
     *
     * @param context 上下文信息
     * @param service 服务
     * @return Future
     */
    private Future<Integer> initConf(CodeContext context, CompletionService<Integer> service) {
        return service.submit(() -> {
            Properties prop = context.getProperties();
            Conf conf = new Conf();
            context.setConf(conf);
            conf.setAuthor(prop.getProperty("author"));
            conf.setVersion(prop.getProperty("version"));
            conf.setEmail(prop.getProperty("email"));
            conf.setCopyright(prop.getProperty("copyright"));
            return 1;
        });
    }

    /**
     * <pre>
     *  初始化数据库配置
     * </pre>
     *
     * @param context 上下文
     * @param service 服务
     * @return Future<T>
     */
    private Future<Integer> initDb(CodeContext context, CompletionService<Integer> service) {
        return service.submit(() -> {
            Properties prop = context.getProperties();
            DbConf conf = new DbConf();
            context.setDb(conf);

            conf.setUrl(prop.getProperty("jdbc.url"));
            conf.setUsername(prop.getProperty("jdbc.username"));
            conf.setPassword(prop.getProperty("jdbc.password"));
            conf.setType(prop.getProperty("type"));
            conf.setTables(prop.getProperty("tables"));
            conf.setPrefix(prop.getProperty("tables.prefix"));
            conf.setSuffix(prop.getProperty("tables.suffix"));
            String fieldStr = prop.getProperty("exclude.field");
            if (Objects.nonNull(fieldStr)) {
                conf.setExcludeField(fieldStr.split(","));
            }
            return 1;
        });
    }

    /**
     * <pre>
     *  初始化包
     * </pre>
     *
     * @param context 上下文
     * @param service 服务
     * @return Future
     */
    private Future<Integer> initPackage(CodeContext context, CompletionService<Integer> service) {
        return service.submit(() -> {
            Properties prop = context.getProperties();
            PackageConf conf = new PackageConf();
            context.setPackageConf(conf);

            conf.setBasePackage(prop.getProperty("base.package"));
            conf.setModel(prop.getProperty("core.model.package"));
            conf.setQuery(prop.getProperty("core.query.package"));
            conf.setParam(prop.getProperty("core.param.package"));
            conf.setApi(prop.getProperty("core.api.package"));
            conf.setService(prop.getProperty("core.service.package"));
            conf.setDal(prop.getProperty("core.dal.package"));
            conf.setXml(prop.getProperty("core.xml.package"));
            return 1;
        });
    }

    /**
     * <pre>
     * 初始化文件扩展
     * </pre>
     *
     * @param context 上下文
     * @param service 服务
     * @return Future
     */
    private Future<Integer> initExt(CodeContext context, CompletionService<Integer> service) {
        return service.submit(() -> {
            Properties prop = context.getProperties();
            ExtConf conf = new ExtConf();
            context.setExt(conf);
            conf.setParamSuffix(prop.getProperty("core.param.suffix"));
            conf.setQuerySuffix(prop.getProperty("core.query.suffix"));
            conf.setModelSuffix(prop.getProperty("core.model.suffix"));
            conf.setApiPrefix(prop.getProperty("core.api.prefix"));
            conf.setApiSuffix(prop.getProperty("core.api.suffix"));
            conf.setServicePrefix(prop.getProperty("core.service.prefix"));
            conf.setServiceSuffix(prop.getProperty("core.service.suffix"));
            conf.setServiceImplSuffix(prop.getProperty("core.service.impl.suffix"));
            conf.setDaoPrefix(prop.getProperty("core.dao.prefix"));
            conf.setDaoSuffix(prop.getProperty("core.dao.suffix"));
            conf.setXmlSuffix(prop.getProperty("core.xml.suffix"));
            return 1;
        });
    }

    /**
     * <pre>
     * 初始化框架配置
     * </pre>
     *
     * @param context 上下文
     * @param service 服务
     * @return Future
     */
    private Future<Integer> initFrame(CodeContext context, CompletionService<Integer> service) {
        return service.submit(() -> {
            Properties prop = context.getProperties();
            FrameConf conf = new FrameConf();
            context.setFrame(conf);

            conf.setBasePackage(prop.getProperty("framework.base.package"));
            conf.setApiPackage(prop.getProperty("framework.api.package"));
            conf.setApiSubClass(prop.getProperty("framework.api.subclass"));
            conf.setExceptionPackage(prop.getProperty("framework.exception.package"));
            conf.setExceptionSubClass(prop.getProperty("framework.exception.subclass"));
            conf.setDataPackage(prop.getProperty("framework.data"));
            conf.setDomainSubClass(prop.getProperty("framework.data.domain.subclass"));
            conf.setQuerySubClass(prop.getProperty("framework.data.query.subclass"));
            conf.setParamSubClass(prop.getProperty("framework.data.req.subclass"));
            conf.setRespSubClass(prop.getProperty("framework.data.resp.subclass"));
            conf.setPagePackage(prop.getProperty("framework.page.package"));
            conf.setPageClass(prop.getProperty("framework.page.param.class"));
            conf.setPageResultClass(prop.getProperty("framework.page.result.class"));
            conf.setRespClass(prop.getProperty("framework.resp.class"));
            conf.setValidatePackage(prop.getProperty("framework.validate.package"));
            conf.setValidateClass(prop.getProperty("framework.validate.class"));
            return 1;
        });
    }


}
